/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/memory
// Copyright( c) 2013.  All Rights Reserved
//
// File:		AEEngineStats.h
// Author:		Gianluca Belardelli
// Date:		14/04/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEENGINESTATS_H_
#define _AEENGINESTATS_H_

/// <summary>
/// The Instrumentation class collects and records performance stats about
/// the various parts of the system.
/// 
/// It is hooked in to the framework and is updated from within the scheduler.
/// It caches performance stats until they are needed for display.
///
/// This class implements the service Instrumentation interface, and is a Singleton.
/// </summary>
/// <seealso cref="IService::Instrumentation">
class AEEngineStats
{
	AE_DECLARE_SINGLETON( AEEngineStats );

// Members
private:
	AEFLOAT32			m_fCurrentFPS;
	AEUINT32			m_uiCPUCount;
	AEUINT32			m_uiNumCounters;
	AEUINT32			m_uiActiveThreadCount;

	AEDOUBLE64			*m_dCPUPercentCounters;

	AEFLOAT32			m_fSecondsSinceLastUpdate;
	AEINT32				m_nFramesSinceLastUpdate;

	AEINT64				m_nLastUpdateTick;
	AEINT64				*m_lpnAccumulatingFrameTicks;

	AEFLOAT32			*m_lpfLastFrameRatio;
	//std::vector<void *>	m_vecProcessorCounters;
	AETArray<void *>	m_vecProcessorCounters;
	// Index of the performance object called "Processor" in English.
	// From registry, in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PerfLib\<your language ID>.
	static const AEINT32	m_nProcessorObjectIndex = 238;
	
	// Take a guess at how long the name could be in all languages of the "Processor" counter object.
	static const AEINT32	m_nProcessorObjectNameMaxSize = 128;

	/// <summary cref="Instrumentation::m_secondsPerUpdate">
	///		Update interval - this is how often this object will refresh its data from its sources.
	/// </summary>
	static const AEFLOAT32	m_fSecondsPerUpdate;

// Methods
public:
	/// <summary cref=Instrumentation::~Instrumentation>
	///		Basic destructor.
	/// </summary>
	~AEEngineStats ( void );
	
	/// <summary cref="Instrumentation::UpdatePeriodicData">
	///		This function drives the instrumentation; it's called regularly from
	///		the scheduler in the framework, to let the instrumentation know that another
	///		frame has elapsed.  Whenever it is called, this function will make sure that
	///		the cached stats used by the instrumentation are up to date; if they've gotten
	///		too old, it will refresh those stats.
	/// </summary>
	/// <param name="deltaTime">f32 - Elapsed wall-clock time since the last call to this function.</param>
	void UpdatePeriodicData( AEFLOAT32 fDeltaTime );

	/// <summary cref=Instrumentation::getCPUCount>
	///		Get the number of available CPUs in the system, including physical and logical CPUs.
	/// </summary>
	/// <returns>i32 - Number of available CPUs in the system.</returns>
	AE_FORCEINLINE AEUINT32 GetCPUCount( void ) { return m_uiCPUCount; }

	/// <summary cref=Instrumentation::getCurrentFPS>
	///		Get the most recently-measured frame rate (in Frames Per Second).  This value is
	///		automatically refreshed.  It is averaged over the last few frames (defined by the
	///		update interval in this class).
	/// </summary>
	/// <returns>f32 - Frame rate, in frames per second.</returns>
	/// <seealso cref="Instrumentation::m_secondsPerUpdate"/>
	AE_FORCEINLINE AEFLOAT32 GetCurrentFPS( void ) { return m_fCurrentFPS; };

	/// <summary cref=Instrumentation::getNumCounters>
	///		Get the number of CPU performance counters that we're using.  There will be one for
	///		each available CPU, and one more for the total.
	/// </summary>
	/// <returns>i32 - Number of CPU performance counters, which will be returned by the getCPUCounters call.</returns>
	AE_FORCEINLINE AEUINT32 GetNumCounters( void ) { return m_uiNumCounters; };

	/// <summary cref=Instrumentation::getCPUCounters>
	///		Get the most recently measured CPU counters.  This value is automatically refreshed.
	/// </summary>
	/// <param name="CPUPercent">
	///		f64* - Array, filled by this call, of CPU counters showing percent CPU load.
	///		Must be big enough to hold all counters, see Instrumentation::getNumCounters().
	/// </param>
	void GetCPUCounters( AEDOUBLE64 *dCPUPercent );

	/// <summary cref=Instrumentation::setActiveThreadCount>
	///		Set the number of threads the application will now run.
	/// </summary>
	/// <param name="activeThreadCount">i32 - Number of active threads the app should use now.</param>
	AE_FORCEINLINE void SetActiveThreadCount( AEUINT32 uiActiveThreadCount ) { m_uiActiveThreadCount = uiActiveThreadCount; }

	/// <summary cref=Instrumentation::getActiveThreadCount>
	///		Get the number of threads that we're currently using in this application.
	/// </summary>
	/// <returns>i32 - Current active thread count.</returns>
	AE_FORCEINLINE AEUINT32 GetActiveThreadCount( void ) { return m_uiActiveThreadCount; }

	/// <summary cref=Instrumentation::CaptureJobCounterTicks>
	///		Called when some job has finished.  Keep track of how much time this job has spent in this frame.
	///		There may be many jobs of one type passed in during a single frame; their results will be appended.
	/// </summary>
	/// <param name="jobType">u32 - The type of the job that has just completed; a member of System::Types.</param>
	/// <param name="jobCounterTicks">i64 - The number of clock ticks, from _RDTSC, that this job used during this frame.</param>
	void CaptureJobCounterTicks( AEUINT32 uiJobType, AEINT64 nJobCounterTicks );

	/// <summary cref=Instrumentation::getJobCount>
	///		Get the max number of job types possible in the system, so the caller can allocate the right sized array.
	/// </summary>
	/// <returns>i32 - Max number of job types.</returns>
	//AE_FORCEINLINE AEUINT32 GetJobCount( void ) { return (AEUINT32)System::Types::MAX; }

	/// <summary cref=Instrumentation::getJobRatios>
	///		Get the ratios of job work done in this most recent frame.
	/// </summary>
	/// <param name="jobRatios">
	///		f32* - Array that this function should fill with the ratios of time spent in each workload on this frame.
	///		Must be the right length; call getJobCount.
	/// </param>
	void GetJobRatios( AEFLOAT32 *lpfJobRatios );
};

#endif // _AEENGINESTATS_H_

